package com.cbarmstrong.Finance;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Logger;

public class PairCollection {
	
	private HashMap<String, ArrayList<String>> groups=new HashMap<String, ArrayList<String>>();
	private Logger logger;
	
	public PairCollection(){
		logger = Data.getLogger("PairCollection");
	}
	
	public PairCollection(Logger logger){
		this.logger=logger;
	}
	
	public void createPairs() throws SQLException{
		groups=new HashMap<String, ArrayList<String>>();
		//System.out.println("Initialised pair collection");
		int i=0;
		Connection con = Data.initConnection();
		Statement s = con.createStatement();
		while(System.getProperties().containsKey("set."+i)){
			String group=System.getProperty("set."+i).split("-")[0];
			String def=System.getProperty("set."+i).split("-")[1];
			addToGroup(def,group);
			if(s.executeUpdate("INSERT INTO indicator_definition VALUES ( '"+group+"' , '"+def+"' )")!=1){ logger.severe("Failed to insert "+def); }
			logger.info("Inserted definition "+def);
			i++;
		}
		if(System.getProperty("onlyGenerateDefinitions").compareTo("true")==0){ logger.info("Exiting due to parms."); return; }
		try {
			createPairs();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		Logger logger=Data.getLogger("PairCollection.createPairs");
		Connection connection=Data.initConnection();
		PreparedStatement indicatorInsert=connection.prepareStatement("INSERT IGNORE INTO indicators VALUES ( default, ? )");
		PreparedStatement systemIndicator=connection.prepareStatement("INSERT INTO system_indicators VALUES ( ? , ? )");
		PreparedStatement systemEntry=connection.prepareStatement("INSERT INTO systems VALUES ( ? , ? )");
		Statement querySystem=connection.createStatement();
		ResultSet r1;
		Set<String> keys=groups.keySet();
		long max, init;//, lastId;
		int count;
		for(String key : keys){
			for(i=0;i<groups.get(key).size();i++){
				for(int j=0;j<groups.get(key).size();j++){
					indicatorInsert.setString(1, groups.get(key).get(i)+" "+groups.get(key).get(j));
					indicatorInsert.execute();
				}
			}
		}
		s=connection.createStatement();
		r1=s.executeQuery("SELECT max(id),min(id) from indicators");
		r1.first();
		max=r1.getLong("max(id)");
		init=r1.getLong("min(id)");		
		Long[] data=new Long[new Integer(System.getProperty("maxSystemDepth"))];
		data[0]=init-1;
		count=1;
		if(System.getProperty("resetIndicators")!=null){
				querySystem.executeUpdate("DELETE FROM systems");
				querySystem.executeUpdate("DELETE FROM system_indicators");
		}
		r1=s.executeQuery("select indicator from system_indicators where system=(select max(id) from systems)");
		i=0;
		while(r1.next()){
			data[i++]=r1.getLong("indicator");
		}
		logger.info("Starting point for indicator addition:");
		logger.info(Arrays.toString(data));
		int pendingUpdates=0;
		long systemCount=1;
		while(true){
			//String join="";
			data[0]++;
			//String clause="( SELECT * from system_indicators where indicator="+data[0]+") i0, ";
			for (i=0;i<data.length-1;i++){
				if(data[i]!=null){
					if(data[i]>max-i){
						if(data[i+1]==null){
							data[i+1]=init;
							count++;
						} else{ data[i+1]++; }
						data[i]=data[i+1]+1;
					}
					if(data[i+1]!=null){ 
						//clause+="( SELECT * from system_indicators where indicator="+data[i+1]+") i"+(i+1)+", "; 
						//join +=" AND i"+i+".system=i"+(i+1)+".system ";
					}
				}
			}
			//System.out.println("SELECT i0.system FROM "+clause+" ( SELECT * from systems where indicator_count="+count+") s1 WHERE s1.id=i0.system "+join);
			//r1=querySystem.executeQuery("SELECT i0.system FROM "+clause+" ( SELECT * from systems where indicator_count="+count+") s1 WHERE s1.id=i0.system "+join);
			//if(r1.first()){ System.out.println("Duplicaton - continuing"); continue; }
			systemEntry.setLong(1, systemCount);
			systemEntry.setInt(2, count);
			systemEntry.addBatch();
			//r1=querySystem.executeQuery("SELECT last_insert_id()");
			//r1.first();
			//lastId=r1.getLong("last_insert_id()");
			systemIndicator.setLong(1, systemCount++);
			for(i=0;i<data.length;i++){
				if(data[i]==null){ break; }
				systemIndicator.setLong(2, data[i]);
				systemIndicator.addBatch();
				pendingUpdates++;
			}
			if(pendingUpdates>10000){ 
				systemEntry.executeBatch(); 
				systemIndicator.executeBatch(); 
				pendingUpdates=0; 
			}
			if(data[data.length-1]!=null && data[data.length-1]==max-data.length){ break; }
		}
	}
	
	public void addToGroup(String indicator, String group){
		if(groups.containsKey(group)){ groups.get(group).addAll(expandDeclaration(indicator)); }
		else{ groups.put(group, expandDeclaration(indicator)); }
	}
	
	public ArrayList<String> expandDeclaration(String indicator){
		ArrayList<String> expanded=new ArrayList<String>();
		String[] parms = indicator.split(":");
		//logger.fine("Expanding "+indicator);
		if(parms[0].compareToIgnoreCase("level")==0){
			for(double i=new Double(parms[1]); i<new Double(parms[2]); i=i+new Double(parms[3])){
				expanded.add(parms[0]+","+i);
			}
		}
		if(parms[0].compareToIgnoreCase("ema")==0 || 
				parms[0].compareToIgnoreCase("sma")==0 ||
				parms[0].compareToIgnoreCase("rsi")==0 ||
				parms[0].compareToIgnoreCase("wil")==0 ||
				parms[0].compareToIgnoreCase("stoch")==0){
			parms=indicator.split(":",5);
			for(int i=new Integer(parms[1]);i<new Integer(parms[2]);i=i+new Integer(parms[3])){
				ArrayList<String> indicators=expandDeclaration(parms[4]);
				Iterator<String> iterator = indicators.iterator();
				while(iterator.hasNext()){ 
					expanded.add(parms[0]+","+i+","+iterator.next()); 
					//System.out.println("Added "+expanded.get(expanded.size()-1)); 
				}
			}
		}
		if(parms[0].compareToIgnoreCase("macd")==0){
			ArrayList<String> indicators1=expandDeclaration(parms[1].replace(";", ":"));
			ArrayList<String> indicators2=expandDeclaration(parms[2].replace(";", ":"));
			Iterator<String> iterator1 = indicators1.iterator();
			while(iterator1.hasNext()){
				Iterator<String> iterator2 = indicators2.iterator();
				String ind1 = (String) iterator1.next();
				while(iterator2.hasNext()){
					expanded.add("macd,"+ind1.replace(",", ".")+","+((String) iterator2.next()).replace(",","."));
					//System.out.println("Added "+expanded.get(expanded.size()-1));
				}
			}
		}
		if(parms[0].compareToIgnoreCase("macdHist")==0){
			ArrayList<String> indicators1=expandDeclaration(parms[1].replace(";", ":"));
			ArrayList<String> indicators2=expandDeclaration(parms[2].replace(";", ":"));
			Iterator<String> iterator1 = indicators1.iterator();
			while(iterator1.hasNext()){
				Iterator<String> iterator2 = indicators2.iterator();
				String ind1 = (String) iterator1.next();
				while(iterator2.hasNext()){
					String ind2 = (String) iterator2.next();
					for(int i=new Integer(parms[3]);i<new Integer(parms[4]);i=i+new Integer(parms[5])){
						expanded.add("macdHist,"+ind1.replace(",", ".")+","+ind2.replace(",",".")+","+i);
						//System.out.println("Added "+expanded.get(expanded.size()-1));
					}
				}
			}
		}
		if(parms[0].compareToIgnoreCase("diff")==0){
			parms=indicator.split(":",5);
			for(int i=new Integer(parms[1]);i<new Integer(parms[2]);i=i+new Integer(parms[3])){
				ArrayList<String> indicators=expandDeclaration(parms[4]);
				Iterator<String> iterator=indicators.iterator();
				while(iterator.hasNext()){
					expanded.add("diff,"+i+","+iterator.next());
					//System.out.println("Added "+expanded.get(expanded.size()-1));
				}
			}
		}
		if(parms[0].compareToIgnoreCase("open")==0 ||
				parms[0].compareToIgnoreCase("close")==0 ||
				parms[0].compareToIgnoreCase("high")==0 ||
				parms[0].compareToIgnoreCase("low")==0 ||
				parms[0].compareToIgnoreCase("wc")==0){
			expanded.add(parms[0]);
			//System.out.println("Added "+expanded.get(expanded.size()-1));
		}
		if(parms[0].compareToIgnoreCase("ohlc")==0){
			expanded.add("open");
			expanded.add("close");
			expanded.add("high");
			expanded.add("low");
			//System.out.println("Added ohlc items");
		}
		// bbUpper,ema.5.close,ohlc,2,2
		// bb : ema;1;10;2;close : close : 1 : 5 : 1 : 1 : 5 : 1
		if(parms[0].compareToIgnoreCase("bb")==0){
			ArrayList<String> emas = expandDeclaration(parms[1].replace(";", ":"));
			ArrayList<String> vals = expandDeclaration(parms[2].replace(";", ":"));
			for(int i=new Integer(parms[3]);i<new Integer(parms[4]);i=i+new Integer(parms[5])){
				for(int j=new Integer(parms[6]);j<new Integer(parms[7]);j=j+new Integer(parms[8])){
					Iterator<String> iEmas=emas.iterator();
					while(iEmas.hasNext()){
						String nextE = iEmas.next();
						Iterator<String> iVals = vals.iterator();
						while(iVals.hasNext()){
							String nextV = iVals.next();
							//logger.fine("Adding: bbUpper,"+nextE.replace(",", ".")+","+nextV+","+i+","+j);
							expanded.add("bbUpper,"+nextE.replace(",", ".")+","+nextV+","+i+","+j);
							expanded.add("bbLower,"+nextE.replace(",", ".")+","+nextV+","+i+","+j);
						}
					}
				}
			}	
		}
		return expanded;
	}
	
}
